﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using DirectShowLib;
using DirectShowLib.DES;
using System.Collections.Generic;
using MediaInfoNet;

namespace MediaPlayer
{
    public class MediaInfo
    {
        //public List<AudioStreamInfo> Audio = new List<AudioStreamInfo>();
        //public List<VideoStreamInfo> Video = new List<VideoStreamInfo>();
        //public TimeSpan Duration = TimeSpan.FromSeconds(0);

        public static Tuple<List<AudioStreamInfo>, List<VideoStreamInfo>> Parse(string file)
        {
            MediaFile aviFile = new MediaFile(file);

            List<AudioStreamInfo> audioStreams = new List<AudioStreamInfo>();
            List<VideoStreamInfo> videoStreams = new List<VideoStreamInfo>();

            if (!System.IO.File.Exists(file)) throw new ArgumentException(file);

            IMediaDet mediaDet = (IMediaDet)new MediaDet();

            try
            {
                DsError.ThrowExceptionForHR(mediaDet.put_Filename(file));
            }
            catch
            {
                return null;
            }

            int i = 0;
            Guid streamGuid = Guid.Empty;
            int numStreams;

            mediaDet.get_OutputStreams(out numStreams);

            while (i < numStreams)
            {
                mediaDet.put_CurrentStream(i++);
                mediaDet.get_StreamType(out streamGuid);

                if (streamGuid == DirectShowLib.MediaType.Video)
                {
                    AMMediaType mediaType = new AMMediaType();
                    mediaDet.get_StreamMediaType(mediaType);
                    if (mediaType.formatType != FormatType.VideoInfo) throw new Exception("Unknown video format");

                    VideoInfoHeader videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(mediaType.formatPtr, typeof(VideoInfoHeader));

                    VideoStreamInfo video = new VideoStreamInfo();
                    video.Width = videoInfo.BmiHeader.Width;
                    video.Height = videoInfo.BmiHeader.Height;

                    double frameRate;
                    mediaDet.get_FrameRate(out frameRate);
                    video.FrameRate = frameRate;

                    double length;
                    mediaDet.get_StreamLength(out length);
                    video.Duration = TimeSpan.FromSeconds(length);

                    video.Frames = (int)(frameRate * length);

                    video.SubType = mediaType.subType;
                    videoStreams.Add(video);

                    DsUtils.FreeAMMediaType(mediaType);
                    mediaType = null;
                }
                else if (streamGuid == DirectShowLib.MediaType.Audio)
                {
                    AMMediaType mediaType = new AMMediaType();
                    mediaDet.get_StreamMediaType(mediaType);
                    if (mediaType.formatType != FormatType.WaveEx) throw new Exception("Unknown audio format");

                    var audioInfo = Marshal.PtrToStructure(mediaType.formatPtr, typeof(WaveFormatEx)) as WaveFormatEx;

                    AudioStreamInfo audio = new AudioStreamInfo();
                    audio.Size = audioInfo.cbSize;
                    audio.AverageBytesPerSec = audioInfo.nAvgBytesPerSec;
                    audio.BlockAlign = audioInfo.nBlockAlign;
                    audio.Channels = audioInfo.nChannels;
                    audio.SamplesPerSecond = audioInfo.nSamplesPerSec;
                    audio.BitsPerSample = audioInfo.wBitsPerSample;
                    audio.FormatTag = audioInfo.wFormatTag;
                    audio.Khz = audio.SamplesPerSecond / 1000;
                    audio.Kbps = (audio.AverageBytesPerSec * 8) / 1000;

                    double length;
                    mediaDet.get_StreamLength(out length);
                    audio.Duration = TimeSpan.FromSeconds(length);

                    audio.SubType = mediaType.subType;
                    audioStreams.Add(audio);

                    DsUtils.FreeAMMediaType(mediaType);
                    mediaType = null;
                }
                else
                {
                    throw new Exception("Unknown Media Type: " + streamGuid);
                }
            }

            // Get more details
            FileInfo fileInfo = new System.IO.FileInfo(file);
            //Dictionary<string, string> b = fileInfo.GetDetails();
            KeyValuePair<string, string> sysLength = fileInfo.GetDetail(FileDetails.Length);

            if (sysLength.Value != null && sysLength.Value != string.Empty)
            {
                foreach (var stream in audioStreams)
                {
                    if (stream.Duration == TimeSpan.FromSeconds(0))
                    {
                        stream.Duration = TimeSpan.Parse(sysLength.Value);
                    }
                }

                foreach (var stream in videoStreams)
                {
                    if (stream.Duration == TimeSpan.FromSeconds(0))
                    {
                        stream.Duration = TimeSpan.Parse(sysLength.Value);
                    }
                }
            }

            return Tuple.Create(audioStreams, videoStreams);
        }

        //public MediaInfo(string file)
        //{
        //    if (!File.Exists(file)) throw new ArgumentException(file);

        //    IMediaDet mediaDet = (IMediaDet)new MediaDet();

        //    try
        //    {
        //        DsError.ThrowExceptionForHR(mediaDet.put_Filename(file));
        //    }
        //    catch
        //    {
        //        return;
        //    }

        //    int i = 0;
        //    Guid streamGuid = Guid.Empty;
        //    int numStreams;

        //    mediaDet.get_OutputStreams(out numStreams);

        //    while (i < numStreams)
        //    {
        //        mediaDet.put_CurrentStream(i++);
        //        mediaDet.get_StreamType(out streamGuid);

        //        if (streamGuid == DirectShowLib.MediaType.Video)
        //        {
        //            AMMediaType mediaType = new AMMediaType();
        //            mediaDet.get_StreamMediaType(mediaType);
        //            if (mediaType.formatType != FormatType.VideoInfo) throw new Exception("Unknown video format");

        //            VideoInfoHeader videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(mediaType.formatPtr, typeof(VideoInfoHeader));

        //            VideoStreamInfo video = new VideoStreamInfo();
        //            video.Width = videoInfo.BmiHeader.Width;
        //            video.Height = videoInfo.BmiHeader.Height;

        //            double frameRate;
        //            mediaDet.get_FrameRate(out frameRate);
        //            video.FrameRate = frameRate;

        //            double length;
        //            mediaDet.get_StreamLength(out length);
        //            video.Duration = TimeSpan.FromSeconds(length);

        //            if (video.Duration > this.Duration)
        //            {
        //                this.Duration = video.Duration;
        //            }

        //            video.Frames = (int)(frameRate * length);

        //            video.SubType = mediaType.subType;
        //            this.Video.Add(video);

        //            DsUtils.FreeAMMediaType(mediaType);
        //            mediaType = null;
        //        }
        //        else if (streamGuid == DirectShowLib.MediaType.Audio)
        //        {
        //            AMMediaType mediaType = new AMMediaType();
        //            mediaDet.get_StreamMediaType(mediaType);
        //            if (mediaType.formatType != FormatType.WaveEx) throw new Exception("Unknown audio format");

        //            var audioInfo = Marshal.PtrToStructure(mediaType.formatPtr, typeof(WaveFormatEx)) as WaveFormatEx;

        //            AudioStreamInfo audio = new AudioStreamInfo();
        //            audio.Size = audioInfo.cbSize;
        //            audio.AverageBytesPerSec = audioInfo.nAvgBytesPerSec;
        //            audio.BlockAlign = audioInfo.nBlockAlign;
        //            audio.Channels = audioInfo.nChannels;
        //            audio.SamplesPerSecond = audioInfo.nSamplesPerSec;
        //            audio.BitsPerSample = audioInfo.wBitsPerSample;
        //            audio.FormatTag = audioInfo.wFormatTag;
        //            audio.Khz = audio.SamplesPerSecond / 1000;
        //            audio.Kbps = (audio.AverageBytesPerSec * 8) / 1000;

        //            double length;
        //            mediaDet.get_StreamLength(out length);
        //            audio.Duration = TimeSpan.FromSeconds(length);

        //            if (audio.Duration > this.Duration)
        //            {
        //                this.Duration = audio.Duration;
        //            }

        //            audio.SubType = mediaType.subType;
        //            this.Audio.Add(audio);

        //            DsUtils.FreeAMMediaType(mediaType);
        //            mediaType = null;
        //        }
        //        else
        //        {
        //            throw new Exception("Unknown Media Type: " + streamGuid);
        //        }
        //    }

        //    if (this.Duration == TimeSpan.FromSeconds(0))
        //    {
        //        // Get more details
        //        FileInfo a = new System.IO.FileInfo(file);
        //        //Dictionary<string, string> b = a.GetDetails();
        //        KeyValuePair<string, string> c = a.GetDetail(FileDetails.Length);

        //        if (c.Value != null && c.Value != string.Empty)
        //        {
        //            this.Duration = TimeSpan.Parse(c.Value);
        //        }
        //    }
        //}
    }
}
